package fr.ants.controller;

import java.util.concurrent.BlockingQueue;

import fr.ants.model.Ant;
import fr.ants.model.Grid;
import fr.ants.model.Nest;
import fr.ants.model.Node;
import fr.ants.model.stats.CycleStatistic;
import fr.ants.model.stats.NestStatistics;
import fr.ants.model.stats.SimulatorStatistics;

/**
 * <p>It is the simulator of the application.</p>
 * 
 * @author Vianney DUPOY DE GUITARD
 */
public class Simulator {

	/** Statistics grabber. */
	private SimulatorStatistics stats = new SimulatorStatistics();

	/** The grid used by this simulator. */
	private Grid grid;

	/**
	 * Creates a simulator for a specific grid.
	 * @param pGrid : the grid to use.
	 */
	public Simulator(Grid pGrid) {
		grid = pGrid;
	}

	/** 
	 * Executes the simulation algorithms on the grid.
	 */
	public void execute() {
		try {
			// Grab all the nests.
			BlockingQueue<Nest> nests = grid.getNests();
			CycleStatistic cycleStats = stats.newCycle();

			// Use logic for each nest.
			for (Nest nest : nests) {
				nest.next();
				NestStatistics nestStats = cycleStats.newNest();

				// Use logic for each ant.
				for (int i = 0; i < nest.getAnts().size(); i++) {
					Ant ant = nest.getAnts().get(i);
					ant.next(grid);

					// Checking ant state for statistics.
					switch (ant.getState()) {
					case WALKING_NEST:
						nestStats.increaseAntToNestSteps();
						nestStats.addResourcesInTransit(ant.getFood());
						break;
					case FOLLOW:
						nestStats.increaseAntFollowSteps();
						break;
					case EXPLORING:
						nestStats.increaseAntExploreSteps();
						break;
					case CROP:
						nestStats.increaseAntCrops();
						break;
					case DEPOSE:
						nestStats.increaseAntDeposits();
						nestStats.addResourcesInTransit(ant.getFood());
						break;
					}
				}

				// Gather the stats.
				nestStats.setAntCount(nest.getAnts().size());
				nestStats.setResourceCount(nest.getResourceCount());
			}

			// Use logic for each node.
			for (int x = 0; x < grid.getSizeX(); x++) {
				for (int y = 0; y < grid.getSizeY(); y++) {
					Node n = grid.getNode(x, y);
					n.dissipatePheromones();
					n.regenResource();
					if (n.getResource() != null) {
						cycleStats.addResourcesAvailable(n.getResource().getAmount());
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/** @return the grid. */
	public Grid getGrid() {
		return grid;
	}

	/**
	 * Changes the grid.
	 * @param grid : the new grid.
	 */
	public void setGrid(Grid grid) {
		this.grid = grid;
	}

	/**
	 * @return the stats
	 */
	public SimulatorStatistics getStats() {
		return stats;
	}
}